﻿using Hangfire.Client;
using Hangfire.Common;
using Hangfire.Logging;
using Hangfire.Server;
using Hangfire.States;
using Hangfire.Storage;

namespace Identification.Importer.Core.Filter
{
    public class LogEverythingAttribute : JobFilterAttribute, IClientFilter, IServerFilter, IElectStateFilter,
        IApplyStateFilter
    {
        private static readonly ILog Logger = LogProvider.For<LogEverythingAttribute>();

        public void OnCreating(CreatingContext context)
        {
            Logger.InfoFormat("Creating a job based on method `{0}.{1}`...", context.Job.Type.FullName,
                context.Job.Method.Name);
        }

        public void OnCreated(CreatedContext context)
        {
            Logger.InfoFormat(
                "Job that is based on method `{0}.{1}` has been created with id `{2}`",
                context.Job.Type.FullName,
                context.Job.Method.Name,
                context.BackgroundJob?.Id);
        }

        public void OnPerforming(PerformingContext context)
        {
            Logger.InfoFormat(
                "Job that is based on method `{0}.{1}` and with id `{2}` starting to perform",
                context.BackgroundJob.Job.Type.FullName,
                context.BackgroundJob.Job.Method.Name,
                context.BackgroundJob?.Id);
        }

        public void OnPerformed(PerformedContext context)
        {
            Logger.InfoFormat(
                "Job that is based on method `{0}.{1}` and with id `{2}` has been performed",
                context.BackgroundJob.Job.Type.FullName,
                context.BackgroundJob.Job.Method.Name,
                context.BackgroundJob?.Id);
        }

        public void OnStateElection(ElectStateContext context)
        {
            if (context.CandidateState is FailedState failedState)
            {
                Logger.WarnFormat(
                    "Job that is based on method `{0}.{1}` and with id `{2}` has been failed due to an exception `{3}`",
                    context.BackgroundJob.Job.Type.FullName,
                    context.BackgroundJob.Job.Method.Name,
                    context.BackgroundJob?.Id,
                    failedState.Exception);
            }
        }

        public void OnStateApplied(ApplyStateContext context, IWriteOnlyTransaction transaction)
        {
            Logger.InfoFormat(
                "Job that is based on method `{0}.{1}` and with id `{2}` state was changed from `{3}` to `{4}`",
                context.BackgroundJob.Job.Type.FullName,
                context.BackgroundJob.Job.Method.Name,
                context.BackgroundJob?.Id,
                context.OldStateName,
                context.NewState.Name);
        }

        public void OnStateUnapplied(ApplyStateContext context, IWriteOnlyTransaction transaction)
        {
            Logger.InfoFormat(
                "Job that is based on method `{0}.{1}` and with id `{2}` state `{3}` was unapplied.",
                context.BackgroundJob.Job.Type.FullName,
                context.BackgroundJob.Job.Method.Name,
                context.BackgroundJob?.Id,
                context.OldStateName);
        }
    }
}